package cn.thoughtworks.school.services;

import cn.thoughtworks.school.entities.Serial;
import cn.thoughtworks.school.entities.User;
import cn.thoughtworks.school.entities.Video;
import cn.thoughtworks.school.exceptions.BusinessException;
import cn.thoughtworks.school.repositories.VideoRepository;
import cn.thoughtworks.school.response.SimpleVideoResponse;
import cn.thoughtworks.school.response.VideoResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class VideoService {
  @Autowired
  private VideoRepository videoRepository;

  @Autowired
  private UserCenterService userCenterService;
  @Autowired
  private SubscriptionService subscriptionService;

  public Video createVideo(Video video) {
    return videoRepository.save(video);
  }

  public List<VideoResponse> getMyVideosByOrganization(Long id) {
    Map user = userCenterService.getUserInfo(id);
    Long organizationId = Long.valueOf(user.get("currentOrganizationId").toString());
    return videoRepository.findByCreatorIdAndOrganizationId(id, organizationId)
      .stream()
      .map(video -> VideoResponse.build(user, video))
      .collect(Collectors.toList());
  }

  public void deleteVideo(Long id) throws BusinessException {
    Video video = getVideoOrThrows(id);
    videoRepository.delete(video);
  }

  public VideoResponse getVideo(Long id, User currentUser) throws BusinessException {
    Video video = getVideoOrThrows(id);
    Map user = userCenterService.getUserInfo(video.getCreatorId());
    boolean isCurrentUserNeedSubscribe = isNeedSubscribe(currentUser, video);
    return VideoResponse.build(user, video,isCurrentUserNeedSubscribe);
  }
  private boolean isNeedSubscribe(User currentUser, Video video) {
    if (video.getIsPublic() || currentUser.getId().equals(video.getCreatorId())) {
      return false;
    }
    return subscriptionService.isUserSubscribeVideo(currentUser.getId(), video.getId());
  }
  private Video getVideoOrThrows(Long id) throws BusinessException {
    return videoRepository.findById(id).orElseThrow(() -> new BusinessException("视频不存在"));
  }

  public Video editVideo(Long id, Video video) throws BusinessException {
    Video foundVideo = getVideoOrThrows(id);
    foundVideo.update(video);
    return videoRepository.save(foundVideo);
  }

  public List<SimpleVideoResponse> getTopVideosByOrganization(Long id) {
    Long userCurrentOrganizationId = userCenterService.getUserCurrentOrganizationId(id);
    List<Video> videos = videoRepository.findFirst8ByIsAllVisibleIsTrueAndIsReleaseIsTrueOrOrganizationIdAndIsReleaseIsTrueOrderByCreateTimeDesc(userCurrentOrganizationId);
    return mergeVideosAndUsers(videos);
  }

  public List<SimpleVideoResponse> mergeVideosAndUsers(List<Video> videos) {
    List<Map> users = getUsers(videos);
    return videos.stream()
      .map(video -> {
        Map user = users.stream().filter(item -> Objects.equals(video.getCreatorId(), Long.parseLong(item.get("id").toString())))
          .findFirst().get();
        return SimpleVideoResponse.build(user, video);
      })
      .collect(Collectors.toList());
  }

  private List<Map> getUsers(List<Video> videos) {
    List<Long> userIds = videos.stream()
      .map(Video::getCreatorId)
      .collect(Collectors.toList());

    return userCenterService.getUsersByIds(userIds);
  }

  public PageImpl<SimpleVideoResponse> getPageableVideosByOrganization(Long id, Pageable pageable) {
    Long userCurrentOrganizationId = userCenterService.getUserCurrentOrganizationId(id);
    Page<Video> videoPageable = videoRepository.findByIsAllVisibleIsTrueAndIsReleaseIsTrueOrOrganizationIdAndIsReleaseIsTrueOrderByCreateTimeDesc(userCurrentOrganizationId, pageable);

    List<Video> videos = videoPageable.getContent();
    List<SimpleVideoResponse> simpleVideoResponses = mergeVideosAndUsers(videos);
    return new PageImpl(simpleVideoResponses, pageable, videoPageable.getTotalElements());
  }


  public void removeVideosFromSerial(Serial serial) {
    List<Video> videos = serial.getVideos()
        .stream()
        .map(Video::removeSerial)
        .collect(Collectors.toList());

    videoRepository.saveAll(videos);
  }

  public void removeVideoFromSerial(Long videoId) throws BusinessException {
    Video video = getVideoOrThrows(videoId);
    video.setSerialId(0L);
    videoRepository.save(video);
  }

  public List getMySubscriptionVideos(Long id) {
    List<Video> videos = videoRepository.getMySubscriptionVideos(id);
    return mergeVideosAndUsers(videos);
  }
}
